package blog.generic

/**
 * 泛型
 *java与kotlin不支持直接型变，
型变包括协变与逆变，相当于<? extend A>和<? super B>
Producer-Extends-out-get, Consumer-Super-in-写入-set
协变 out == <? extend A>,逆变 in == <? super B>
 */
fun main(args: Array<String>) {

    //泛型函数  ,截取部分集合元素
    //fun <T> List<T>.slice(indices: IntRange): List<T>
    //泛型函数的调用
    ('a'..'z').toList().slice(0..2).also(::println)

    //可以省略右边<>
    val list1: ArrayList<Int> = ArrayList()

    //kt中List直接支持协变，interface List<out E> ,
    // 因此声明变量处不需要额外加上out，kt支持在类或者接口上加in,out,这样每次声明时不用额外写in,out
    //MutableList相当于java中的List，interface MutableList<E>,不能直接支持型变,需要用到in,out
    //协变,只读不能修改
    val list2: List<Number> = arrayListOf<Int>(1)
    val number: Number = list2[0]
//    list2[1] = 2 ,error

    //相当于java的Producter<? extend Number> p = new Producer<Integer>(1)
    val p: Producer<Number> = Producer(1)
    p.product()


    //逆变
    val list3: MutableList<in Number> = ArrayList<Any>()
    list3.add(3.3)
    //跟java一样可以取，但是类型是Any，没有意义
    val any = list3[0]

    //相当于java：Consumer<? super Number> c = new Consumer<Object>();
    val c: Consumer<Number> = Consumer<Any>()
    c.consume(99)

    //*相当于java的？,不同的是,java这里就算右边确定了具体类型，左边的?仍然表示? extend Object
    //而kt的*则可以表示? extend Int(out Int)
    val l: LimitType<*> = LimitType<Int>()

    //Java 里的数组是支持协变的，而 Kotlin 中的数组 Array 不支持协变。
    //这是因为在 Kotlin 中数组是用 Array 类来表示的，
    // 这个 Array 类使用泛型就和集合类一样，所以不支持协变
    //error
//    val arr:Array< Number> = Array<Int>(1){
//        it
//    }
    //加out支持协变
    val arr: Array<out Number> = Array<Int>(1) {
        it
    }
    arr[0].also(::println)

}

//跟java一样类型擦除，error
//private fun <T> test1(number: Number) {
//    if (number is T){
//
//    }
//}
//可以这样
private fun <T> test1(number: Number, clazz: Class<T>) {
    if (clazz.isInstance(number)) {
    }
}

//更简便的方式
private inline fun <reified T> test2(number: Number) {
    if (number is T) {

    }
}

//error,out,in 只能在类或者接口中添加，不能加在方法上
//private fun <out T> test3(t:T){}


//限定了类型,用where限定符
class LimitType<in L> where L : Number, L : Comparable<L>

abstract class Limit<in L : Number> : Comparable<L>
//---> 另一种写法：abstract class Limit<in L> :Comparable<L> where L:Number


class Producer<out P>(val p: P) {


    fun product(): P {
        println("生产者：只能向外取出，不能往里添加")
        return p
    }
}

class Consumer<in C> {

    fun consume(c: C) {
        println("消费者：可以往里添加修改，也可以向外输出，但是没有意义")
    }

}





